#include <iostream>
#include "compiler/lexer.h"
#include "compiler/parser.h"
#include "compiler/semantic_analyzer.h"
#include "execution/catalog.h"
#include "storage/disk_manager.h"
#include "storage/buffer_pool.h"

int main() {
    std::cout << "Test semantic analyzer started" << std::endl;
    
    try {
        // Create necessary components
        std::string dbFile = "test_semantic_analyze.db";
        auto diskManager = std::make_unique<DiskManager>(dbFile);
        auto bufferPool = std::make_unique<BufferPool>(10, std::move(diskManager));
        auto catalog = std::make_shared<Catalog>(std::move(bufferPool));
        
        // Initialize catalog
        catalog->loadFromStorage();
        
        // Create semantic analyzer
        SemanticAnalyzer analyzer(catalog);
        
        // Test 1: Semantic analysis of CREATE TABLE statement
        std::cout << "\nTest 1: Analyzing CREATE TABLE statement" << std::endl;
        std::string sql1 = "CREATE TABLE test_users (id INT, name VARCHAR, age INT)";
        
        Lexer lexer1(sql1);
        std::vector<Token> tokens1 = lexer1.tokenize();
        Parser parser1(tokens1);
        auto stmt1 = parser1.parse();
        
        std::cout << "Parsing result: " << stmt1->toString() << std::endl;
        
        try {
            analyzer.analyze(stmt1);
            std::cout << "Semantic analysis passed!" << std::endl;
            
            // Actually create the table after successful analysis
            auto createStmt = dynamic_cast<AST::CreateTableStmt*>(stmt1.get());
            if (createStmt) {
                TableInfo tableInfo;
                tableInfo.name = createStmt->tableName;
                
                for (const auto& column : createStmt->columns) {
                    ColumnInfo colInfo;
                    colInfo.name = column.first;
                    colInfo.type = column.second;
                    colInfo.length = 0; // Default length
                    
                    // Handle VARCHAR type length
                    if (colInfo.type.find("VARCHAR") != std::string::npos) {
                        size_t start = colInfo.type.find('(');
                        size_t end = colInfo.type.find(')');
                        if (start != std::string::npos && end != std::string::npos) {
                            std::string lengthStr = colInfo.type.substr(start + 1, end - start - 1);
                            colInfo.length = std::stoi(lengthStr);
                            colInfo.type = "VARCHAR";
                        } else {
                            colInfo.length = 50; // Default length for VARCHAR
                        }
                    }
                    
                    tableInfo.columns.push_back(colInfo);
                }
                
                tableInfo.firstPageId = 0; // Temporarily set to 0
                
                if (catalog->createTable(tableInfo)) {
                    std::cout << "Table '" << tableInfo.name << "' created successfully in catalog." << std::endl;
                    
                    // Save catalog to storage
                    catalog->saveToStorage();
                    
                    // Display table information
                    TableInfo* savedTable = catalog->getTable(tableInfo.name);
                    if (savedTable) {
                        std::cout << "Saved table info: " << savedTable->name << " with " << savedTable->columns.size() << " columns." << std::endl;
                    }
                }
            }
        } catch (const SemanticError& e) {
            std::cerr << "Semantic error: " << e.what() << std::endl;
        }
        
        // Test 2: Semantic analysis of INSERT statement
        std::cout << "\nTest 2: Analyzing INSERT statement" << std::endl;
        std::string sql2 = "INSERT INTO test_users VALUES (1, 'Alice', 30)";
        
        Lexer lexer2(sql2);
        std::vector<Token> tokens2 = lexer2.tokenize();
        Parser parser2(tokens2);
        auto stmt2 = parser2.parse();
        
        std::cout << "Parsing result: " << stmt2->toString() << std::endl;
        
        try {
            analyzer.analyze(stmt2);
            std::cout << "Semantic analysis passed!" << std::endl;
        } catch (const SemanticError& e) {
            std::cerr << "Semantic error: " << e.what() << std::endl;
        }
        
        // Test 3: Semantic analysis of SELECT statement
        std::cout << "\nTest 3: Analyzing SELECT statement" << std::endl;
        std::string sql3 = "SELECT id, name FROM test_users WHERE age > 25";
        
        Lexer lexer3(sql3);
        std::vector<Token> tokens3 = lexer3.tokenize();
        Parser parser3(tokens3);
        auto stmt3 = parser3.parse();
        
        std::cout << "Parsing result: " << stmt3->toString() << std::endl;
        
        try {
            analyzer.analyze(stmt3);
            std::cout << "Semantic analysis passed!" << std::endl;
        } catch (const SemanticError& e) {
            std::cerr << "Semantic error: " << e.what() << std::endl;
        }
        
        // Test 4: Semantic analysis with non-existent table
        std::cout << "\nTest 4: Analyzing statement with non-existent table" << std::endl;
        std::string sql4 = "SELECT * FROM non_existent_table";
        
        Lexer lexer4(sql4);
        std::vector<Token> tokens4 = lexer4.tokenize();
        Parser parser4(tokens4);
        auto stmt4 = parser4.parse();
        
        std::cout << "Parsing result: " << stmt4->toString() << std::endl;
        
        try {
            analyzer.analyze(stmt4);
            std::cout << "Semantic analysis passed!" << std::endl;
        } catch (const SemanticError& e) {
            std::cerr << "Semantic error (expected): " << e.what() << std::endl;
        }
        
        // Clean up test files
        std::remove(dbFile.c_str());
        std::remove("catalog.dat");
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    
    std::cout << "\nTest semantic analyzer finished" << std::endl;
    return 0;
}